//
//  PTCommandESC.m
//  PrinterCommand
//
//  Created by midmirror on 16/3/10.
//  Copyright © 2016年 midmirror. All rights reserved.
//

#import "PTCommandESC.h"

#define tag_Data         @"[DATA]"        //标记要发送给打印机打印图片、条形码、二维码数据
#define tag_Range        @"[RANGE]"       //标记数值的范围
#define tag_Length       @"[LENGTH]"      //标记 ASCII 指令头过后到这一条命令结束的长度
#define tag_Position     @"[POSITION]"    //标记位置
#define tag_Size         @"[SIZE]"        //标记大小（图片的宽高等）
#define tag_CompressSize @"[CPSIZE]"      //压缩后数据的大小

//static Byte *const CR = {0x0d};

@interface PTCommandESC()

@property(strong,nonatomic,readwrite) NSMutableArray *cmdQueue;

@end

@implementation PTCommandESC

- (id)init
{
    if (self = [super init]) {
        [self initCommandQueue];
        self.encoding = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
    }
    return self;
}

- (void)initCommandQueue
{
    _cmdQueue = [[NSMutableArray alloc] init];
}

- (NSMutableArray *)cmdQueue{
    if (!_cmdQueue) {
        _cmdQueue = [[NSMutableArray alloc] init];
    }
    return _cmdQueue;
}

- (void)appendCommand:(NSString *)cmd
{
    [self generateDataWithCMD:cmd DataDict:nil];
}

- (void)appendCommandData:(NSData *)cmdData
{
    [self.cmdQueue addObject:cmdData];
}

- (void)appendCommand:(NSString *)cmd DataDict:(NSDictionary *)dataDict{
    
    [self generateDataWithCMD:cmd DataDict:dataDict];
}

- (NSData *)getCommandData
{
    NSMutableData *cmdData = [[NSMutableData alloc] init];
    
    for (int i = 0; i< _cmdQueue.count; i++) { //发送前把所有指令拼接为一个 NSData
        
        [cmdData appendData:_cmdQueue[i]];
    }
    return cmdData;
}

/** page 306. 传输纸张传感器状态 */
- (void)transmitPaperSonsorStatus
{
    [self appendCommand:@"ESC v"];
}

/** page 412. 初始化打印机 */
- (void)initializePrinter
{
    [self appendCommand:@"ESC @"];
}

/** page 413. 设置页模式 */
- (void)setPageMode
{
    [self appendCommand:@"ESC L"];
}

/** page 158. 在页模式下设置打印区域 */
- (void)pageSetPrintAreaWithXPos:(NSInteger)xPos
                            yPos:(NSInteger)yPos
                           width:(NSInteger)width
                          height:(NSInteger)height
{
    
    NSData *positionData = [self generateDataWithFirst:xPos Second:yPos];
    NSData *sizeData = [self generateDataWithFirst:width Second:height];
    
    NSString *cmd = [[NSString alloc] initWithFormat:@"ESC W [POSITION] [SIZE]"];
    
    [self appendCommand:cmd DataDict:@{tag_Position:positionData,tag_Size:sizeData}];
}

/** page 156. 在页模式下设置打印方向 */
- (void)pageSetPrintDirection:(NSInteger)direction
{
    NSString *cmd = [[NSString alloc] initWithFormat:@"ESC T [%ld]",(long)direction];
    [self appendCommand:cmd];
}

/** page 152. 设置绝对打印位置 */
- (void)setAbsolutePosition:(NSInteger)position
{
    NSString *cmd = [[NSString alloc] initWithFormat:@"ESC $ [LENGTH]"];
    NSData *lengthData = [self generateLengthDataWithDataLength:position Offset:0];
    
    [self appendCommand:cmd DataDict:@{tag_Length:lengthData}];
}

/** page 167. 在页模式下设置绝对垂直打印位置 */
- (void)pageSetAbsoluteYPos:(NSInteger)yPos
{
    NSString *cmd = [[NSString alloc] initWithFormat:@"GS $ [LENGTH]"];
    NSData *lengthData = [self generateLengthDataWithDataLength:yPos Offset:0];
    
    [self appendCommand:cmd DataDict:@{tag_Length:lengthData}];
}

- (void)appendQRCodeData:(NSString *)data
           justification:(NSInteger)justification
              leftMargin:(NSInteger)leftMargin
                eccLevel:(NSInteger)eccLevel
                   model:(NSInteger)model
                    size:(NSInteger)size
{
    [self pageSetPrintAreaWithXPos:0 yPos:0 width:300 height:350];
    [self setJustification:justification]; //1b 61
    [self setLeftMargin:leftMargin]; // 1d 4c
    [self setQRCodeModel:model]; //1d 28 6b 04 00 31 41
    [self setQRCodeModuleSize:size];    //1d 28 6b 03 00 31 43
    [self setQRCodeECCLevel:eccLevel];  //1d 28 6b 03 00 31 45
    [self storeQRCodeData:data];        //1d 28 6b [] [] 31 50 30
    [self printQRCodeData];             //1d 28 6b 03 00 31 51 30
    //    [self setStandardMode]; //1b 53
}

- (void)appendQRCodeData1:(NSString *)data1
                    Data2:(NSString *)data2
            justification:(NSInteger)justification
               leftMargin:(NSInteger)leftMargin
              leftMargin2:(NSInteger)leftMargin2
                 eccLevel:(NSInteger)eccLevel
                    model:(NSInteger)model
                     size:(NSInteger)size
{
    [self initializePrinter];
    [self setPageMode];
    [self pageSetPrintAreaWithXPos:0 yPos:0 width:576 height:350];
    //打印方向
    [self pageSetPrintDirection:0];
    //设置绝对打印位置：距离左边距
    [self setAbsolutePosition:leftMargin];
    //距离上边距
    [self pageSetAbsoluteYPos:10];
    [self setJustification:justification];
    [self setLeftMargin:10];
    [self setQRCodeModel:model];
    [self setQRCodeModuleSize:size];
    [self setQRCodeECCLevel:eccLevel];
    [self storeQRCodeData:data1];
    [self printQRCodeData];
    
    //打印方向
    [self pageSetPrintDirection:0];
    //设置绝对打印位置：距离左边距
    [self setAbsolutePosition:leftMargin2];
    //距离上边距
    [self pageSetAbsoluteYPos:10];
    [self setJustification:justification];
    [self setLeftMargin:10];
    [self setQRCodeModel:model];
    [self setQRCodeModuleSize:size];
    [self setQRCodeECCLevel:eccLevel];
    [self storeQRCodeData:data2];
    [self printQRCodeData];
    [self printAndReturnStandardMode];
    [self cancelPrint];
    
}

- (NSData *)generateLengthDataWithDataLength:(NSUInteger)datalength Offset:(NSInteger)offset{
    NSInteger length = (NSInteger)datalength + offset;
    Byte bytes[2];
    bytes[0] = length & 255;
    bytes[1] = (length >> 8) & 255;
    return [[NSData alloc] initWithBytes:bytes length:2];
}

/** page 169. 设置左边空白宽度 */
- (void)setLeftMargin:(NSInteger)left
{
    NSData *lengthData = [self generateLengthDataWithDataLength:left Offset:0];
    
    // 1d 4c
    [self appendCommand:@"GS L [LENGTH]" DataDict:@{tag_Length:lengthData}];
}

/** page 165. 设置对齐方式 */
- (void)setJustification:(NSInteger)justification
{
    //1b 61
    NSString *cmd = [[NSString alloc] initWithFormat:@"ESC [%ld]",(long)justification];
    [self appendCommand:cmd];
}

/** page 552. 设置模型 */
- (void)setQRCodeModel:(NSInteger)model
{
    //1d 28 6b 04 00 31 41
    NSString *cmd = [[NSString alloc] initWithFormat:@"GS ( k [4] [0] [49] [65] [%ld] [0]",(long)model];
    [self appendCommand:cmd];
}

/** page 553. 设置模型大小 */
- (void)setQRCodeModuleSize:(NSInteger)size
{
    ////1d 28 6b 03 00 31 43
    NSString *cmd = [[NSString alloc] initWithFormat:@"GS ( k [3] [0] [49] [67] [%ld]",(long)size];
    [self appendCommand:cmd];
}

/** page 555. 设置水平校正错误 */
- (void)setQRCodeECCLevel:(NSInteger)level
{
    //1d 28 6b 03 00 31 45
    NSString *cmd = [[NSString alloc] initWithFormat:@"GS ( k [3] [0] [49] [69] [%ld]",(long)level];
    [self appendCommand:cmd];
}

/**
 *  page 557. 储存数据到符号存储区
 */
- (void)storeQRCodeData:(NSString *)data
{
    NSData *qrcodeData = [data dataUsingEncoding:NSASCIIStringEncoding];
    NSData *lengthData = [self generateLengthDataWithDataLength:qrcodeData.length Offset:3];
    
    //1d 28 6b [] [] 31 50 30
    NSString *cmd = [[NSString alloc] initWithFormat:@"GS ( k [LENGTH] 1 P 0 [DATA]"];
    [self appendCommand:cmd DataDict:@{tag_Length:lengthData, tag_Data:qrcodeData}];
}

/** page 559. 打印符号存储区中的符号数据 */
- (void)printQRCodeData
{
    //1d 28 6b 03 00 31 51 30
    NSString *cmd = [[NSString alloc] initWithFormat:@"GS ( k [3] [0] [49] [81] [48]"];
    [self appendCommand:cmd];
}

- (NSData *)generateDataWithFirst:(NSInteger)first Second:(NSInteger)second
{
    Byte bytes[4];
    bytes[0] = first & 255;
    bytes[1] = (first >> 8) & 255;
    bytes[2] = second & 255;
    bytes[3] = (second >> 8) & 255;
    
    return [[NSData alloc] initWithBytes:bytes length:4];
}

/**
 page 67
 在页模式下:
 打印打印机中的所有缓存数据，并将页模式切换至标准模式
 notes:  1.这个命令仅在页模式下有效
 2.打印后打印区域的数据会被删除
 3.这个命令会将ESC W设置的值返回给默认值
 4.使用ESC T设置的值会被保留
 5.打印后，打印位置移动至line的开始。如果设置了左边留白，留白位置为line的开始
 */
- (void)printAndReturnStandardMode
{
    [self appendCommand:@"FF"];
}


/** 在页模式下取消打印数据 */
- (void)cancelPrint
{
    [self appendCommand:@"CAN"];
}

/**
 *  生成指令队列
 *
 *  @param asciiString  ASCII 指令头
 *  @param dataDict         图片、条码、二维码数据
 *
 *  @return 生成的指令队列
 */
- (NSArray *)generateDataWithCMD:(NSString *)asciiString DataDict:(NSDictionary *)dataDict
{
    NSArray *asciiArray = [asciiString componentsSeparatedByString:@" "];
    
    for (int i = 0; i < asciiArray.count; i++) {
        
        NSMutableString *cmd = [[NSMutableString alloc] initWithString:asciiArray[i]];
        if ([self isControlCMD:cmd]) { //属于33个控制字符。
            
        }else if([cmd hasPrefix:@"["] && [cmd hasSuffix:@"]"]) { //取出[]格式的参数
            
            if ([cmd isEqualToString:tag_Data]) {  //如果含有[DATA]，替换为真正的数据
                
                [_cmdQueue addObject:[dataDict objectForKey:tag_Data]];
            }else if([cmd isEqualToString:tag_Length]) {
                
                [_cmdQueue addObject:[dataDict objectForKey:tag_Length]];
            }else if ([cmd isEqualToString:tag_Position]){
                
                [_cmdQueue addObject:[dataDict objectForKey:tag_Position]];
            }else if ([cmd isEqualToString:tag_Size]) {
                
                [_cmdQueue addObject:[dataDict objectForKey:tag_Size]];
            }else if ([cmd isEqualToString:tag_Range]) {
                
                [_cmdQueue addObject:[dataDict objectForKey:tag_Range]];
            }else if ([cmd isEqualToString:tag_CompressSize]) {
                
                [_cmdQueue addObject:[dataDict objectForKey:tag_CompressSize]];
            }else {
                
                // 去除[1] [48] 这样的数字参数
                NSRange range = {1,cmd.length-2};
                NSString *newCMD = [cmd substringWithRange:range];
                Byte bytes = [newCMD intValue];
                NSData *parameterData = [NSData dataWithBytes:&bytes length:1];
                [_cmdQueue addObject:parameterData];
            }
            
        }else { //属于除了33个控制字符剩下的 ASCII 字符
            char *cmdChar = (char *)[cmd UTF8String];
            NSData *data1=[NSData dataWithBytes:cmdChar length:strlen(cmdChar)];//创建不可变的字节对象
            [_cmdQueue addObject:data1];
        }
    }
    return _cmdQueue;
}

- (BOOL)isControlCMD:(NSString *)cmd {
    
    //33 个控制字符（通信专用字符）
    NSString *controlCMD = @"NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RE US DEL";
    NSArray *controlCMDArray = [controlCMD componentsSeparatedByString:@" "];
    
    Byte byte[33] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,127};
    for (int j = 0; j < controlCMDArray.count; j++) { //判断是否属于33个控制字符
        
        if ([cmd isEqualToString:controlCMDArray[j]]) {
            
            NSData *data = [[NSData alloc] initWithBytes:&byte[j] length:1];
            [_cmdQueue addObject:data];
            
            return YES;
        }
    }
    
    return NO;
}

@end

